/*
 * @Author: lzg2021 854378082@qq.com
 * @Date: 2022-06-15 08:59:50
 * @LastEditors: 李志刚
 * @LastEditTime: 2023-01-19 10:38:43
 * @FilePath: \www.firefly.com\resources\js\console\api\http.js
 * @Description: axios封装,请求拦截、响应拦截、错误统一处理，AES/RSA加密解密，base64在url里转义是个坑，需要转成16位
 */
import axios from 'axios';
import func from '../utils/func';
import router from '.././router/router';
import store from '.././store/store'
import { LOGIN } from '.././store/mutation_types'
import ViewUIPlus from 'view-ui-plus'
let queue = [];
let showFlag = false;
function closeSpin(url) {
    queue.pop() // 弹出遵循先进先出原则
    // 为了防止有嵌套接口请求可以使用延时关闭，但是容易引发错误，所以时间尽量小
    setTimeout(() => {
        if (queue.length == 0 && showFlag) { // 如果队列里还有没有完成的请求就不关闭loading效果
            showFlag = false;
            ViewUIPlus.Spin.hide();
        }
    }, 50);
}
/**
  * 跳转登录页
  * 携带当前页面路由，以期在登录页面完成登录后返回当前页面
  */
const toLogin = () => {
    router.replace({
        path: '/',
        query: {
            redirect: router.currentRoute.fullPath
        }
    });
}

/**
  * 请求失败后的错误统一处理
  * @param {Number} status 请求失败的状态码
  */
const errorHandle = (status, other) => {
    // 状态码判断
    switch (status) {
        // 401: 未登录状态，跳转登录页
        case 401:
            store.commit('LOGOUT');
            toLogin();
            break;
        // 验证没通过
        case 422:
            ViewUIPlus.Message.error(other);
            break;

        // 404请求不存在
        case 404:
            ViewUIPlus.Message.error('请求的资源不存在...');
            break;

        default:
            ViewUIPlus.Message.error('服务器有点忙...');
            console.log(other);
            break;
    }
}

// 创建axios实例
const instance = axios.create({ timeout: 1000 * 30 });
// 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
/**
  * 请求拦截器
  * 每次请求前，如果存在token则在请求头中携带token
  */
instance.interceptors.request.use(
    config => {
        // 登录流程控制中，根据本地是否存在token判断用户的登录情况
        // 但是即使token存在，也有可能token是过期的，所以在每次的请求头中携带token
        // 后台根据携带的token判断用户的登录情况，并返回给我们对应的状态码
        // 而后我们可以在响应拦截器中，根据状态码进行一些统一的操作。
        // store.getters.token 这里给存成了变量，不会更新，有点问题
        let token = store.getters.token;
        // console.log('request token',token)
        token && (config.headers.Authorization = token);
        if (!token) {
            token = 'token'
        }
        // GET、POST 的取参数方式不同，坑死，对应的富文本内容也会被过滤，所以只签名了token+time两个字段
        let sign_str = {
            token: token,
            timestamp: (new Date()).getTime()
        }
        const sign = func.getSign(sign_str);
        // const rsa = func.RSAencrypted(token);
        if (config.method == 'get') {
            config.params = {
                ...config.params,
                sign: sign,
                // rsa:rsa,
            }
        } else {
            //  + "&rsa=" + rsa
            config.data = config.data + '&sign=' + sign;
        }
        // console.log(config)
        // 打开遮罩
        queue.push(config.url);
        if(queue.length){
            showFlag = true;
            ViewUIPlus.Spin.show();
        }
        return config;
    },
    error => Promise.error(error))

// 响应拦截器
instance.interceptors.response.use(
    // 请求成功
    res => {
        closeSpin(res.config.url);
        if (res.status === 200) {
            // 状态码判断
            let returnCode = false;
            switch (res.data.code) {
                // 400参数的错误
                case 400:
                    ViewUIPlus.Message.error(res.data.message);
                    break;

                case 422:
                    ViewUIPlus.Message.error(res.data.message);
                    break;

                // 401: 未登录状态，跳转登录页
                case 401:
                    store.commit('LOGOUT');
                    toLogin();
                    break;
                // 402没有接口权限
                case 402:
                    ViewUIPlus.Message.error(res.data.message);
                    break;

                // 403 输入正确，但其它相关数据有问题，拒绝继续执行
                case 403:
                    ViewUIPlus.Message.error(res.data.message);
                    break;

                // 404请求不存在
                case 404:
                    ViewUIPlus.Message.error('请求的资源不存在...');
                    break;

                // 200 正确返回
                case 200:
                    // 把返回的 authorization 放到token里边，刷新token，不刷新只是不能保证一直有效并不是会立即失败
                    let tokenData = {
                        id: store.getters.user_id,
                        name: store.getters.user_name,
                        token: res.headers.authorization,
                    };
                    store.commit(LOGIN, tokenData)
                    // ViewUIPlus.Message.success(res.data.message);
                    // console.log('reponse token: ',localStorage.getItem("token"))
                    Promise.resolve(res)
                    returnCode = true;
                    break;

                default:
                    ViewUIPlus.Message.error('服务器有点忙...');
                    break;
            }
            if(returnCode){
                return res.data;
            }else{
                return Promise.reject(res);
            }
        } else {
            // console.log(res)
            return Promise.reject(res);
        }
    },
    // 请求失败
    error => {
        closeSpin(error.config.url);
        const { response } = error;
        if (response) {
            // 请求已发出，但是不在2xx的范围
            errorHandle(response.status, response.data.message);
            return Promise.reject(response);
        } else {
            // 处理断网的情况
            // eg:请求超时或断网时，更新state的network状态
            // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
            // 关于断网组件中的刷新重新获取数据，会在断网组件中说明
            ViewUIPlus.Message.error('请检查您的网络情况...');
        }
    });

export default instance;
